{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 载入数据\n",
    "data = np.genfromtxt(\"kmeans.txt\", delimiter=\" \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算距离 \n",
    "def euclDistance(vector1, vector2):  \n",
    "    return np.sqrt(sum((vector2 - vector1)**2))\n",
    "  \n",
    "# 初始化质心\n",
    "def initCentroids(data, k):  \n",
    "    numSamples, dim = data.shape\n",
    "    # k个质心，列数跟样本的列数一样\n",
    "    centroids = np.zeros((k, dim))  \n",
    "    # 随机选出k个质心\n",
    "    for i in range(k):  \n",
    "        # 随机选取一个样本的索引\n",
    "        index = int(np.random.uniform(0, numSamples))  \n",
    "        # 作为初始化的质心\n",
    "        centroids[i, :] = data[index, :]  \n",
    "    return centroids  \n",
    "  \n",
    "# 传入数据集和k的值\n",
    "def kmeans(data, k):  \n",
    "    # 计算样本个数\n",
    "    numSamples = data.shape[0]   \n",
    "    # 样本的属性，第一列保存该样本属于哪个簇，第二列保存该样本跟它所属簇的误差\n",
    "    clusterData = np.array(np.zeros((numSamples, 2)))  \n",
    "    # 决定质心是否要改变的变量\n",
    "    clusterChanged = True  \n",
    "  \n",
    "    # 初始化质心  \n",
    "    centroids = initCentroids(data, k)  \n",
    "  \n",
    "    while clusterChanged:  \n",
    "        clusterChanged = False  \n",
    "        # 循环每一个样本 \n",
    "        for i in range(numSamples):  \n",
    "            # 最小距离\n",
    "            minDist  = 100000.0  \n",
    "            # 定义样本所属的簇\n",
    "            minIndex = 0  \n",
    "            # 循环计算每一个质心与该样本的距离\n",
    "            for j in range(k):  \n",
    "                # 循环每一个质心和样本，计算距离\n",
    "                distance = euclDistance(centroids[j, :], data[i, :])  \n",
    "                # 如果计算的距离小于最小距离，则更新最小距离\n",
    "                if distance < minDist:  \n",
    "                    minDist  = distance  \n",
    "                    # 更新样本所属的簇\n",
    "                    minIndex = j  \n",
    "                    # 更新最小距离\n",
    "                    clusterData[i, 1] = distance\n",
    "              \n",
    "            # 如果样本的所属的簇发生了变化\n",
    "            if clusterData[i, 0] != minIndex:  \n",
    "                # 质心要重新计算\n",
    "                clusterChanged = True\n",
    "                # 更新样本的簇\n",
    "                clusterData[i, 0] = minIndex\n",
    "  \n",
    "        # 更新质心\n",
    "        for j in range(k):  \n",
    "            # 获取第j个簇所有的样本所在的索引\n",
    "            cluster_index = np.nonzero(clusterData[:, 0] == j)\n",
    "            # 第j个簇所有的样本点\n",
    "            pointsInCluster = data[cluster_index]  \n",
    "            # 计算质心\n",
    "            centroids[j, :] = np.mean(pointsInCluster, axis = 0) \n",
    "#         showCluster(data, k, centroids, clusterData)\n",
    "  \n",
    "    return centroids, clusterData  \n",
    "  \n",
    "# 显示结果 \n",
    "def showCluster(data, k, centroids, clusterData):  \n",
    "    numSamples, dim = data.shape  \n",
    "    if dim != 2:  \n",
    "        print(\"dimension of your data is not 2!\")  \n",
    "        return 1  \n",
    "  \n",
    "    # 用不同颜色形状来表示各个类别\n",
    "    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']  \n",
    "    if k > len(mark):  \n",
    "        print(\"Your k is too large!\")  \n",
    "        return 1  \n",
    "  \n",
    "    # 画样本点  \n",
    "    for i in range(numSamples):  \n",
    "        markIndex = int(clusterData[i, 0])  \n",
    "        plt.plot(data[i, 0], data[i, 1], mark[markIndex])  \n",
    "  \n",
    "    # 用不同颜色形状来表示各个类别\n",
    "    mark = ['*r', '*b', '*g', '*k', '^b', '+b', 'sb', 'db', '<b', 'pb']  \n",
    "    # 画质心点 \n",
    "    for i in range(k):  \n",
    "        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 20)  \n",
    "  \n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\hokky\\Anaconda3\\lib\\site-packages\\numpy\\core\\fromnumeric.py:3257: RuntimeWarning: Mean of empty slice.\n",
      "  out=out, **kwargs)\n",
      "C:\\Users\\hokky\\Anaconda3\\lib\\site-packages\\numpy\\core\\_methods.py:154: RuntimeWarning: invalid value encountered in true_divide\n",
      "  ret, rcount, out=ret, casting='unsafe', subok=False)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cluster complete!\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 设置k值\n",
    "k = 4  \n",
    "\n",
    "# 注意下面为优化的步骤，见ppt。在sklearn的包中有下属优化的运算步骤。\n",
    "min_loss = 10000  # 比较大的值\n",
    "min_loss_centroids = np.array([])\n",
    "min_loss_clusterData = np.array([])\n",
    "\n",
    "for i in range(50):\n",
    "    # centroids 簇的中心点 \n",
    "    # cluster Data样本的属性，第一列保存该样本属于哪个簇，第二列保存该样本跟它所属簇的误差\n",
    "    centroids, clusterData = kmeans(data, k)  # 4个质心的特征值（所在位置），样本的属性？？\n",
    "    loss = sum(clusterData[:,1])/data.shape[0]\n",
    "    if loss < min_loss:  #小于就更新\n",
    "        min_loss = loss\n",
    "        min_loss_centroids = centroids  # 最小loss对应的质心的属性\n",
    "        min_loss_clusterData = clusterData\n",
    "        \n",
    "#     print('loss',min_loss)\n",
    "print('cluster complete!')      \n",
    "centroids = min_loss_centroids\n",
    "clusterData = min_loss_clusterData\n",
    "\n",
    "# 显示结果\n",
    "showCluster(data, k, centroids, clusterData)\n",
    "\n",
    "# 报警的原因：出现了空值，即有的时候4个质心变3个，就无法平均值计算了。不影响"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 做预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1],\n",
       "       [0, 1],\n",
       "       [0, 1],\n",
       "       [0, 1]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 做预测\n",
    "x_test = [0,1]\n",
    "np.tile(x_test,(k,1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-2.6265299 , -2.10868015],\n",
       "       [ 3.53973889,  3.89384326],\n",
       "       [-2.65077367,  3.79019029],\n",
       "       [ 2.46154315, -1.78737555]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 误差\n",
    "np.tile(x_test,(k,1))-centroids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 6.89865932,  4.44653198],\n",
       "       [12.52975144, 15.16201536],\n",
       "       [ 7.02660103, 14.3655424 ],\n",
       "       [ 6.05919468,  3.19471136]])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 误差平方\n",
    "(np.tile(x_test,(k,1))-centroids)**2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([11.34519129, 27.6917668 , 21.39214343,  9.25390604])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 误差平方和\n",
    "((np.tile(x_test,(k,1))-centroids)**2).sum(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 最小值所在的索引号\n",
    "np.argmin(((np.tile(x_test,(k,1))-centroids)**2).sum(axis=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict(datas):\n",
    "    return np.array([np.argmin(((np.tile(data,(k,1))-centroids)**2).sum(axis=1)) for data in datas])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 画出簇的作用区域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 获取数据值所在的范围\n",
    "x_min, x_max = data[:, 0].min() - 1, data[:, 0].max() + 1\n",
    "y_min, y_max = data[:, 1].min() - 1, data[:, 1].max() + 1\n",
    "\n",
    "# 生成网格矩阵\n",
    "xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),\n",
    "                     np.arange(y_min, y_max, 0.02))\n",
    "\n",
    "z = predict(np.c_[xx.ravel(), yy.ravel()])# ravel与flatten类似，多维数据转一维。flatten不会改变原始数据，ravel会改变原始数据\n",
    "z = z.reshape(xx.shape)\n",
    "# 等高线图\n",
    "cs = plt.contourf(xx, yy, z)\n",
    "# 显示结果\n",
    "showCluster(data, k, centroids, clusterData)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
